package com.key.w8.http1.connection;

import com.key.w8.http1.handler.AbstractHttp1Initializer;
import com.key.w8.http1.handler.Http1FullHandlerBuilder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.SupportedCipherSuiteFilter;

import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Arrays;
import java.util.List;



/**
 * @Author: k8
 * @CreateTime: 2025-03-06
 * @Version: 1.0
 */
public class Http1ConnectionInitializer extends AbstractHttp1Initializer {
    private List<String> cipherSuites = Arrays.asList(
            "TLS_AES_128_GCM_SHA256",
            "TLS_AES_256_GCM_SHA384",
            "TLS_CHACHA20_POLY1305_SHA256"
    );

    private final String crtPath;
    private final String privateKeyPath;

    private final boolean isServer;
    public Http1ConnectionInitializer(ConnectionBuilder connectionBuilder,Http1FullHandlerBuilder builder, boolean sslEnable, String tlsProtocol, String crtPath,String privateKeyPath,boolean isServer) {
        super(connectionBuilder,builder, sslEnable,tlsProtocol,isServer);
        this.crtPath = crtPath;
        this.privateKeyPath = privateKeyPath;
        this.isServer = isServer;
    }

    public Http1ConnectionInitializer(Connection connection, Http1FullHandlerBuilder builder, boolean sslEnable, String tlsProtocol, boolean isServer, String crtPath,String privateKeyPath) {
        super(connection, builder, sslEnable,tlsProtocol, isServer);
        this.crtPath = crtPath;
        this.privateKeyPath = privateKeyPath;
        this.isServer = isServer;
    }


    @Override
    public SslContext configSslContext(String tlsProtocol) throws Exception {
        if (isServer){
            return configSslContextServer(tlsProtocol);
        }else {
            return configSslContextClient(tlsProtocol);
        }
    }
    // 移除ALPN协议配置（HTTP/1.x不需要应用层协议协商）‌:ml-citation{ref="2,3" data="citationList"}
                    /* 原HTTP/2相关配置
                    .applicationProtocolConfig(new ApplicationProtocolConfig(
                        ApplicationProtocolConfig.Protocol.ALPN,
                        ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
                        ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
                        ApplicationProtocolNames.HTTP_2))
                    */
    // 删除ALPN协议配置‌:ml-citation{ref="7" data="citationList"}
                /* 原HTTP/2相关配置
                .applicationProtocolConfig(new ApplicationProtocolConfig(
                    ApplicationProtocolConfig.Protocol.ALPN,
                    ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
                    ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
                    ApplicationProtocolNames.HTTP_2))
                */

    private SslContext configSslContextServer(String tlsProtocol) throws Exception {
        try (InputStream crtIn = getInputStream(crtPath);
             InputStream privateKeyIn = getInputStream(privateKeyPath)) {

            final SslProvider provider = SslProvider.isAlpnSupported(SslProvider.OPENSSL)
                    ? SslProvider.OPENSSL : SslProvider.JDK;

            SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(crtIn, privateKeyIn)
                    .sslProvider(provider)
                    .protocols(tlsProtocol);
            if ("TLSv1.3".equalsIgnoreCase(tlsProtocol)) {
                sslContextBuilder.ciphers(cipherSuites); // 明确指定TLSv1.3套件
            } else if ("TLSv1.2".equalsIgnoreCase(tlsProtocol)) {
                sslContextBuilder.ciphers(null, SupportedCipherSuiteFilter.INSTANCE); // 使用默认TLSv1.2
            } else {
                throw new IllegalArgumentException("Unsupported TLS protocol: " + tlsProtocol);
            }

            return sslContextBuilder.build();
        }
    }

    private SslContext configSslContextClient(String tlsProtocol) throws Exception {
        final SslProvider provider = SslProvider.isAlpnSupported(SslProvider.OPENSSL)
                ? SslProvider.OPENSSL : SslProvider.JDK;

        SslContextBuilder sslContextBuilder = SslContextBuilder.forClient()
                .sslProvider(provider)
                .protocols(tlsProtocol)
                .trustManager(getTrustManagerFactory());

        if ("TLSv1.3".equalsIgnoreCase(tlsProtocol)) {
            sslContextBuilder.ciphers(cipherSuites);
        } else if ("TLSv1.2".equalsIgnoreCase(tlsProtocol)) {
            sslContextBuilder.ciphers(null, SupportedCipherSuiteFilter.INSTANCE);
        } else {
            throw new IllegalArgumentException("Unsupported TLS protocol: " + tlsProtocol);
        }

        return sslContextBuilder.build();
    }
    private TrustManagerFactory getTrustManagerFactory() throws CertificateException,
            IOException, KeyStoreException, NoSuchAlgorithmException {
        // 获取默认的 keystore 类型（通常是 JKS）
        String keyType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyType);

        // 加载默认的 keystore（cacerts 文件），通常 cacerts 位于 JAVA_HOME/lib/security/cacerts
        try (InputStream in = new FileInputStream(System.getProperty("java.home") + "/lib/security/cacerts")) {
            keyStore.load(in, "changeit".toCharArray());  // 默认密码是 changeit
        }

        // 获取默认的 TrustManagerFactory 算法
        String algorithm = TrustManagerFactory.getDefaultAlgorithm();

        // 创建 TrustManagerFactory 并初始化
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);
        trustManagerFactory.init(keyStore);

        return trustManagerFactory;
    }
    private TrustManagerFactory getTrustManagerFactory2() throws CertificateException,
            IOException, KeyStoreException, NoSuchAlgorithmException {
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        Certificate ca;
        try(InputStream in = getInputStream(crtPath)) {
            ca = factory.generateCertificate(in);
        }
        String keyType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("certificate", ca);
        String algorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);
        trustManagerFactory.init(keyStore);
        return trustManagerFactory;
    }
    private InputStream getInputStream(String path){
        InputStream inputStream;
        try {
            inputStream = new FileInputStream(path);
        } catch (FileNotFoundException e) {
            inputStream = this.getClass().getResourceAsStream(path);
            if (inputStream == null){
                inputStream = this.getClass().getClassLoader().getResourceAsStream(path);
            }
        }
        if (inputStream == null){
            throw new RuntimeException("this Path is not available.");
        }
        return inputStream;
    }


}
